/* Threats function to scan the
game space to find sequences of 1, 2, or 3
colours in a row, returning the number of
'threats' of each strength that were
found */


#include "threats.h"

// Index into a 1-d array as if it were 2-d
#define CELL(board, x, y, cols) (board [ y*cols + x ])
#define HASHED(scanHash, x, y, dir, cols) ( CELL(scanHash, x, y, cols) & ( 1 << dir ) )
#define SETHASH(scanHash, x, y, dir, cols) ( CELL(scanHash, x, y, cols) |= ( 1 << dir ) )

extern int rows;
extern int cols;
extern int last_move;
extern int total_time;
extern int player_1_time;
extern int last_move_time;

static int *scanHash;

int RUNVALS[] = {
0,//bbbb,0x00
0,//bbbr,0x01
0,//bbbg,0x02
0,//bbbs,0x03
0,//bbrb,0x04
0,//bbrr,0x05
0,//bbrg,0x06
0,//bbrs,0x07
0,//bbgb,0x08
0,//bbgr,0x09
0,//bbgg,0x0a
-RUN_A,//bbgs,0x0b
0,//bbsb,0x0c
0,//bbsr,0x0d
-RUN_A,//bbsg,0x0e
-RUN_E,//bbss,0x0f
0,//brbb,0x10
0,//brbr,0x11
0,//brbg,0x12
0,//brbs,0x13
0,//brrb,0x14
0,//brrr,0x15
0,//brrg,0x16
0,//brrs,0x17
0,//brgb,0x18
0,//brgr,0x19
0,//brgg,0x1a
0,//brgs,0x1b
0,//brsb,0x1c
0,//brsr,0x1d
0,//brsg,0x1e
0,//brss,0x1f
0,//bgbb,0x20
0,//bgbr,0x21
0,//bgbg,0x22
-RUN_C,//bgbs,0x23
0,//bgrb,0x24
0,//bgrr,0x25
0,//bgrg,0x26
0,//bgrs,0x27
0,//bggb,0x28
0,//bggr,0x29
0,//bggg,0x2a
-RUN_B,//bggs,0x2b
-RUN_B,//bgsb,0x2c
0,//bgsr,0x2d
-RUN_D,//bgsg,0x2e
-RUN_G,//bgss,0x2f
0,//bsbb,0x30
0,//bsbr,0x31
-RUN_D,//bsbg,0x32
-RUN_I,//bsbs,0x33
0,//bsrb,0x34
0,//bsrr,0x35
0,//bsrg,0x36
0,//bsrs,0x37
-RUN_B,//bsgb,0x38
0,//bsgr,0x39
-RUN_A,//bsgg,0x3a
-RUN_I,//bsgs,0x3b
-RUN_H,//bssb,0x3c
0,//bssr,0x3d
-RUN_I,//bssg,0x3e
-RUN_J,//bsss,0x3f
0,//rbbb,0x40
0,//rbbr,0x41
0,//rbbg,0x42
0,//rbbs,0x43
0,//rbrb,0x44
0,//rbrr,0x45
0,//rbrg,0x46
0,//rbrs,0x47
0,//rbgb,0x48
0,//rbgr,0x49
0,//rbgg,0x4a
0,//rbgs,0x4b
0,//rbsb,0x4c
0,//rbsr,0x4d
0,//rbsg,0x4e
0,//rbss,0x4f
0,//rrbb,0x50
0,//rrbr,0x51
0,//rrbg,0x52
0,//rrbs,0x53
0,//rrrb,0x54
0,//rrrr,0x55
0,//rrrg,0x56
0,//rrrs,0x57
0,//rrgb,0x58
0,//rrgr,0x59
0,//rrgg,0x5a
RUN_A,//rrgs,0x5b
0,//rrsb,0x5c
0,//rrsr,0x5d
RUN_A,//rrsg,0x5e
RUN_E,//rrss,0x5f
0,//rgbb,0x60
0,//rgbr,0x61
0,//rgbg,0x62
0,//rgbs,0x63
0,//rgrb,0x64
0,//rgrr,0x65
0,//rgrg,0x66
RUN_C,//rgrs,0x67
0,//rggb,0x68
0,//rggr,0x69
0,//rggg,0x6a
RUN_B,//rggs,0x6b
0,//rgsb,0x6c
RUN_B,//rgsr,0x6d
RUN_D,//rgsg,0x6e
RUN_G,//rgss,0x6f
0,//rsbb,0x70
0,//rsbr,0x71
0,//rsbg,0x72
0,//rsbs,0x73
0,//rsrb,0x74
0,//rsrr,0x75
RUN_C,//rsrg,0x76
RUN_I,//rsrs,0x77
0,//rsgb,0x78
RUN_B,//rsgr,0x79
RUN_B,//rsgg,0x7a
RUN_I,//rsgs,0x7b
0,//rssb,0x7c
RUN_H,//rssr,0x7d
RUN_I,//rssg,0x7e
RUN_J,//rsss,0x7f
0,//gbbb,0x80
0,//gbbr,0x81
0,//gbbg,0x82
-RUN_C,//gbbs,0x83
0,//gbrb,0x84
0,//gbrr,0x85
0,//gbrg,0x86
0,//gbrs,0x87
0,//gbgb,0x88
0,//gbgr,0x89
0,//gbgg,0x8a
-RUN_D,//gbgs,0x8b
-RUN_C,//gbsb,0x8c
0,//gbsr,0x8d
-RUN_B,//gbsg,0x8e
-RUN_G,//gbss,0x8f
0,//grbb,0x90
0,//grbr,0x91
0,//grbg,0x92
0,//grbs,0x93
0,//grrb,0x94
0,//grrr,0x95
0,//grrg,0x96
RUN_C,//grrs,0x97
0,//grgb,0x98
0,//grgr,0x99
0,//grgg,0x9a
RUN_D,//grgs,0x9b
0,//grsb,0x9c
RUN_C,//grsr,0x9d
RUN_B,//grsg,0x9e
RUN_G,//grss,0x9f
0,//ggbb,0xa0
0,//ggbr,0xa1
0,//ggbg,0xa2
-RUN_B,//ggbs,0xa3
0,//ggrb,0xa4
0,//ggrr,0xa5
0,//ggrg,0xa6
RUN_B,//ggrs,0xa7
0,//gggb,0xa8
0,//gggr,0xa9
0,//gggg,0xaa
0,//gggs,0xab
-RUN_B,//ggsb,0xac
RUN_B,//ggsr,0xad
0,//ggsg,0xae
0,//ggss,0xaf
-RUN_A,//gsbb,0xb0
0,//gsbr,0xb1
-RUN_B,//gsbg,0xb2
-RUN_I,//gsbs,0xb3
0,//gsrb,0xb4
RUN_A,//gsrr,0xb5
RUN_B,//gsrg,0xb6
RUN_I,//gsrs,0xb7
-RUN_D,//gsgb,0xb8
RUN_D,//gsgr,0xb9
0,//gsgg,0xba
0,//gsgs,0xbb
-RUN_I,//gssb,0xbc
RUN_I,//gssr,0xbd
0,//gssg,0xbe
0,//gsss,0xbf
0,//sbbb,0xc0
0,//sbbr,0xc1
-RUN_C,//sbbg,0xc2
-RUN_F,//sbbs,0xc3
0,//sbrb,0xc4
0,//sbrr,0xc5
0,//sbrg,0xc6
0,//sbrs,0xc7
-RUN_C,//sbgb,0xc8
0,//sbgr,0xc9
-RUN_A,//sbgg,0xca
-RUN_G,//sbgs,0xcb
-RUN_H,//sbsb,0xcc
0,//sbsr,0xcd
-RUN_I,//sbsg,0xce
-RUN_J,//sbss,0xcf
0,//srbb,0xd0
0,//srbr,0xd1
0,//srbg,0xd2
0,//srbs,0xd3
0,//srrb,0xd4
0,//srrr,0xd5
RUN_C,//srrg,0xd6
RUN_F,//srrs,0xd7
0,//srgb,0xd8
RUN_C,//srgr,0xd9
RUN_A,//srgg,0xda
RUN_G,//srgs,0xdb
0,//srsb,0xdc
RUN_H,//srsr,0xdd
RUN_I,//srsg,0xde
RUN_J,//srss,0xdf
-RUN_A,//sgbb,0xe0
0,//sgbr,0xe1
-RUN_D,//sgbg,0xe2
-RUN_G,//sgbs,0xe3
0,//sgrb,0xe4
RUN_A,//sgrr,0xe5
RUN_D,//sgrg,0xe6
RUN_G,//sgrs,0xe7
-RUN_B,//sggb,0xe8
RUN_B,//sggr,0xe9
0,//sggg,0xea
0,//sggs,0xeb
-RUN_I,//sgsb,0xec
RUN_I,//sgsr,0xed
0,//sgsg,0xee
0,//sgss,0xef
-RUN_E,//ssbb,0xf0
0,//ssbr,0xf1
-RUN_G,//ssbg,0xf2
-RUN_J,//ssbs,0xf3
0,//ssrb,0xf4
RUN_E,//ssrr,0xf5
RUN_G,//ssrg,0xf6
RUN_J,//ssrs,0xf7
-RUN_G,//ssgb,0xf8
RUN_G,//ssgr,0xf9
0,//ssgg,0xfa
0,//ssgs,0xfb
-RUN_J,//sssb,0xfc
RUN_J,//sssr,0xfd
0,//sssg,0xfe
0//ssss,0xff
};

static int numTriplets;

int threats ( char *board )
{
    int val = 0;
    numTriplets = 0;
    val += partialruns ( board );
    //if ( numTriplets > 1 )
   //     return 5*val;
   // else
        return val;
}

int partialruns ( char *board )
{
    int i, j;
    int val=0;

    scanHash = malloc ( sizeof(int) * cols * rows);
    for ( i = 0; i < cols; i++ )
        for ( j = 0; j < rows; j++ )
            scanHash[i + j*cols] = 0;

#if DBG
// print board to verify
    for (j = rows - 1; j >= 0; j--)
       for (i = 0; i < cols; i++) {
          printf("%c", CELL(board,i,j,cols) );
          if (i == cols - 1)
              printf("\n");
       }
    printf("\n");
#endif


    // Scan on a column-major order so that when we can break
    // upon encountering an empty space
    for ( i = 0; i < cols; i++ ) {
        for ( j = 0; j < rows; j++ ) {
            switch ( CELL(board,i,j,cols) ) {
                case 's':
                    val += threats_scanCell ( i, j, board );
                    break;
                default :
                    break;
            }
        }
    } 
    // No win
    free ( scanHash );

    return val;
}

int threats_scanCell ( int x, int y, char *board )
{
#if DEBUG
    printf("Scanning (%d,%d)\n", x, y);
#endif
    int val = 0;
    
    // Horizontal from left to right
    val += threats_scanEast ( x, y, board);
    val += threats_scanNorthEast ( x, y, board);
	val += threats_scanNorthWest ( x, y, board);
	val += threats_scanNorth ( x, y, board);

	return val;
}

int threats_scanEast ( int x, int y, char *board )
{   
#if DEBUG3
    printf("scanEast: (%d,%d)\n",x,y);
#endif
    int i, r;
    int min_i;
    int max_i; 
    char run[4];
	int val = 0;

    // Horizontal from left to right
    min_i  = x - 3;
    if ( x < 3 )
        min_i = 0;

    max_i = x;
    if ( x > cols - 4 )
        max_i = cols - 4;

    for ( i = min_i; i <= max_i; i++ ) {
        // Skip this run if it has already been checked
        if ( HASHED(scanHash,i,y,EAST,cols) )
            continue;
        // Now we are checking it, so hash it
        SETHASH(scanHash,i,y,EAST,cols);

        for ( r = i; r < i + 4; r++ ) {
            run[r-i] = CELL(board,r,y,cols);
        }
		
		val += runval(run);
		

        }
     
    return val;
}// End horizontal from left to right



int threats_scanNorth ( int x, int y, char *board  )
{   
    int i, r;
    int min_i;
    int max_i; 
    char run[4];
	int val = 0;


    // Vertical from South to North
    min_i  = y - 3;
    if ( y < 3 )
        min_i = 0;

    max_i = y;
    if ( y > rows - 4 )
        max_i = rows - 4;

    for ( i = min_i; i <= max_i; i++ ) {
        // Skip this run if it has already been checked
        if ( HASHED(scanHash,x,i,NORTH,cols) )
            continue;
        // Now we are checking it, so hash it
        SETHASH(scanHash,x,i,NORTH,cols);

        for ( r = i; r < i + 4; r++ ) {
				run[r-i] = CELL(board,x,r,cols);
            }
		
		val += runval(run);		

        }
	return val;
    } // End vertical from South to North




int threats_scanNorthEast ( int  x, int  y, char *board )
{
#if DEBUG
    printf("entered scanNorthEast\n");
#endif
    int i, j, r, s;
    int min_i;
    int max_i;
    int min_j;
    int max_j; 
    char run[4];
	int val = 0;

    // Diagonal from bottom left to top right

    // First get the x boundaries
    for ( r = 0; r < 4; r++) {
        if ( (x - r >= 0) && (y - r >= 0) ) {
            min_i = x - r;
            min_j = y - r;
        }
    }
    max_i = x;
    if ( x > cols - 4 )
        max_i = cols - 4;

    // And then the y boundaries
    max_j = y;
    if (y > rows - 4 )
        max_j = rows - 4;

    i = min_i;
    j = min_j;

    while ( (i <= max_i) && (j <= max_j) ) {

        // Skip this run if it has already been checked
        if ( HASHED(scanHash,i,j,NORTHEAST,cols) ) {

            i++;
            j++;
            continue;
        }
        // Now we are checking it, so hash it
        SETHASH(scanHash,i,j,NORTHEAST,cols);
        r = i;
        s = j;
        while ( ( r < i + 4) && ( s < j + 4 ) ) {

			run[r-i] = CELL(board,r,s,cols);
						

            r++;
            s++;
			}
			
			val += runval(run);

		i++;
	    j++;
			
        }

		return val;

    } // End diagonal from bottom left to top right


int threats_scanNorthWest ( int x, int y, char *board )
{
#if DEBUG2
    printf("entered scanNorthWest (%d,%d)\n",x,y);
#endif
    int i, j, r, s;
    int min_i;
    int max_i;
    int min_j;
    int max_j; 
    char run[4];
	int val = 0;

    // Diagonal from bottom right to top left
    // First get the x boundaries

    min_i  = x;
    if ( x < 3 )
        min_i = 3;

    for ( r = 0; r < 4; r++) {
        if ( (x + r <= cols - 1) && (y - r >= 0) ) {
            max_i = x + r;
            min_j = y - r;
        }
    }
    // And then the y boundaries
    max_j = y;
    if (y > rows - 4 )
        max_j = rows - 4;

    i = max_i;
    j = min_j;
#if DEBUG2
    printf("scanNorthWest: min_i = %d, max_i = %d, min_j = %d,"
           " max_j = %d\n", min_i, max_i, min_j, max_j);
#endif
    while ( (i >=min_i) && (j <= max_j) ) {
#if DEBUG2
        printf("scanNorthWest: (i,j) = (%d,%d)\n", i, j);
#endif

        // Skip this run if it has already been checked
        if ( HASHED(scanHash,i,j,NORTHWEST,cols) ) {
#if DEBUG2
            printf("scanNorthWest: skipping (i,j) = (%d,%d)\n", i, j);
#endif
            i--;
            j++;
            continue;
        }
        // Now we are checking it, so hash it
        SETHASH(scanHash,i,j,NORTHWEST,cols);
        //for ( r = i; r < i + 4; r++ ) {
        r = i;
        s = j;
        while ( ( r >= i - 3) && ( s < j + 4 ) ) {
#if DEBUG2
            printf("scanNorthWest: cell(board,%d,%d,cols) = %c\n", r, s,CELL(board,r,s,cols) );
#endif

			run[s-j] = CELL(board,r,s,cols);

            r--;
            s++;
        }
#if DEBUG2
        printf("scanNorthWest: bc = %d, gc = %d, rc = %d\n", bc, gc, rc);
#endif
		val += runval(run);       

 		i--;
        j++;
#if DEBUG
        printf("scanNorthWest: exiting ij while loop\n");
#endif
    } // End diagonal from bottom left to top right
    return val;
}

/*
int runval ( char *run )
{
	printf("\n%c,%c,%c,%c",run[0],run[1],run[2],run[3]);
	return 0;
}*/



int runval ( char *run )
{
    int i;
    uint8_t idx = 0;
    // Compute index:
    // B => 00
    // R => 01
    // G => 10
    // S => 11
    for (i = 3; i >= 0; i--) {
        switch (run[3-i]) {
            case 'b':
                idx |= (0x0 << (2*i));
                break;
            case 'r':
                idx |= (0x1 << (2*i));
                break;
            case 'g':
                idx |= (0x2 << (2*i));
                break;
            case 's':
                idx |= (0x3 << (2*i));
                break;
        }
    }
//dbg
//    printf("idx=%d\n",idx);
//
    if ((RUNVALS[idx] >= RUN_D) || (RUNVALS[idx] <= -RUN_D))
        numTriplets++;
    return RUNVALS[idx];
}

